<template>
  <div class="map-container">
    <div id="map"></div>
    <ToolTips ref="toolTipRef" @handleOperat="handleOperat" />
    <CompassButton ref="compassRef" @rotate="handleRotate" />
    <LonAndLat :mapZoomIndex="mapZoomIndex" :coordinate="MapCoordinate" />
  </div>
</template>
<script setup>
  import ToolTips from './tool/index.vue';
  import LonAndLat from './lonAndLat/index.vue';
  import CompassButton from './compass/index.vue';
  // vue
  import { onMounted, ref, reactive, watch } from 'vue';
  // js
  import MapJS from './js/index.js';
  import MethodsJS from './js/methods.js';
  import ShipJS from './js/ship.js';
  import DrawJS from './js/draw.js';
  import * as UtilMethods from './js/util.js';
  import DrawMethods from './tool/draw';
  import { dateFormat } from '/@/utils/date';
  // api
  import { api as fusionTrackApi } from '/@/api/plat/fusion-track.js';
  import { api as areaApi } from '/@/api/plat/area.js';

  const toolTipRef = ref();
  const compassRef = ref();

  // 海图对象
  let mapTarget = reactive(null);
  // 中心点
  let MapCoordinate = ref([0, 0]);
  // 图层级别
  let mapZoomIndex = ref(0);
  // layer集合
  let layerList = {
    ship: null,
  };
  // source集合
  let sourceList = {
    ship: null,
  };
  // 轨迹集合
  let travelList = {};
  // 常量ids
  const domId = {
    tipId: 'onContextMenuId',
    EquipmentId: 'typhoon_info_tips_id',
    shipId: 'ship_info_id',
  };
  // 记录显示的船舶ID
  let showShipId = 0;
  const areaList = ref([]);

  let MapConfig = {
    center: [119.45206246145788, 29.17467466774048],
    zoom: 14,
    EPSGCode: 'EPSG:3857',
    mapZIndexLimit: [14, 18],
    shipZoomLimit: [12, 16],
    target: 'map', // 元素节点
  };
  // 初始化海图
  const initMainMap = () => {
    mapTarget = MapJS.initMap(MapConfig);
    MapJS.initGraticule(mapTarget);
    MapJS.initScaleLine(mapTarget);
    initMapMethod(mapTarget);
    // 绘制各种设备
    MethodsJS.drawCamera(mapTarget);
    MethodsJS.drawRadar(mapTarget);
    // 绘制区域
    drawArea(mapTarget);
    // 初始化船舶图层
    const { layer, source } = ShipJS.initShipLayer();
    mapTarget.addLayer(layer);
    layerList.ship = layer;
    sourceList.ship = source;
    showWatchPoint(waterData.value);
    MethodsJS.drawBridgeList(mapTarget);
  };
  // 水位计数据
  const waterData = ref({
    value: 22,
    status: true,
  });

  // 初始化海图事件
  function initMapMethod() {
    // 鼠标移动
    mapTarget.on('pointermove', (evt) => {
      // 鼠标变手
      mapTarget.getTargetElement().style.cursor = mapTarget.hasFeatureAtPixel(evt.pixel) ? 'pointer' : '';
      MapCoordinate.value = UtilMethods.transformNowToLonlat(evt.coordinate);
      var feature = mapTarget.forEachFeatureAtPixel(evt.pixel, function (feature) {
        return feature;
      });

      const fnList = {
        CameraPoint: {
          fn: 'handleEquipmentPoint',
          params: {
            id: domId.EquipmentId,
          },
        },
        RadarPoint: {
          fn: 'handleEquipmentPoint',
          params: {
            id: domId.EquipmentId,
          },
        },
        ship: {
          fn: 'handleShipPoint',
          params: {
            id: domId.shipId,
          },
        },
        mockPoint: {
          fn: 'handleMockPoint',
          params: {
            id: domId.shipId,
          },
        },
      };
      if (feature) {
        const type = feature.get('featureType');
        if (type) {
          // 显示船舶轨迹单独处理
          if (fnList[type].fn === 'handleShipPoint') {
            const detail = feature.get('detail');
            handleShipPoint(mapTarget, detail, fnList[type].params);
            showShipId = detail.targetId;
          } else {
            MethodsJS[fnList[type].fn](mapTarget, feature.get('detail'), fnList[type].params);
          }
        } else {
          pointerOut();
        }
      } else {
        pointerOut();
      }
    });

    // 鼠标移出事件
    function pointerOut() {
      UtilMethods.removeDomById(domId.EquipmentId);
      UtilMethods.removeDomById(domId.shipId);
      if (showShipId) {
        DrawJS.removeLayer(mapTarget, `tarvel_${showShipId}`);
        showShipId = 0;
      }
    }

    // 点击事件
    mapTarget.on('click', (evt) => {
      // 判断是否存在右击菜单，若存在，删掉
      UtilMethods.removeDomById(domId.tipId);
      // 根据坐标查找到对应位置的feature
      const lonAndLat = UtilMethods.transformNowToLonlat(evt.coordinate);
      console.log('lonAndLat: ', lonAndLat);
      var feature = mapTarget.forEachFeatureAtPixel(evt.pixel, function (feature) {
        return feature;
      });
      if (feature) {
        if (feature.id_ && feature.values_.mapCodeType === 'ship') {
          // 船舶点击事件
          // this.shipOnClick(feature)
        }
      }
    });

    // 右击事件
    mapTarget.getViewport().oncontextmenu = (event) => {
      // 去除浏览器自带的菜单事件
      event.preventDefault();
    };

    // 关键事件：地图缩放的时候触发事件
    var mview = mapTarget.getView();
    mapZoomIndex.value = mview.getZoom();
    mapTarget.on('movestart', () => {});
    mapTarget.on('moveend', () => {
      // 监听层级变化
      if (mview.getZoom() !== mapZoomIndex.value) {
        mapZoomIndex.value = mview.getZoom();
      }
    });
  }

  onMounted(initMainMap);

  // 向外抛出的事件
  function deviceSelect(row) {
    UtilMethods.moveToCenterByLonAndLat([row.longitude, row.latitude], mapTarget, 16, 500);
  }

  // 船舶移动
  function mqttGetGps(row) {
    // 低速全部过滤掉
    if (row.speed < 0.1) return;
    ShipJS.drawBaseShip(row, sourceList.ship);
    // 前端记录轨迹并绘制
    if (!travelList[row.targetId]) {
      travelList[row.targetId] = {
        type: 'local',
        list: [row],
      };
    } else {
      // 绘制轨迹的时候，需要判断当前的数据是虚拟AIS(1)还是真实AIS(2)
      if (row.dataType === '2') {
        let lastIndex = -1;
        let arr = travelList[row.targetId].list;
        for (let i = arr.length - 1; i >= 0; i--) {
          if (arr[i].dataType === '2') {
            lastIndex = i;
            break;
          }
        }
        // 删除最后一个 dataType 为 2 之后的所有元素
        if (lastIndex !== -1) {
          arr = arr.slice(0, lastIndex + 1);
        }
        arr.push(row);
        travelList[row.targetId].list = arr;
      } else {
        travelList[row.targetId].list.push(row);
      }
    }
    if (showShipId === row.targetId) {
      DrawJS.drawTravel(mapTarget, travelList[row.targetId].list, `tarvel_${row.targetId}`);
    }
  }

  function handleShipPoint(map = mapTarget, row, params) {
    DrawJS.removeLayer(mapTarget, `tarvel_${showShipId}`);
    if (travelList[row.targetId].type === 'local') {
      travelList[row.targetId].type = 'api';
      // 重新获取轨迹记录，绘制船舶轨迹，并替换之前的缓存
      fusionTrackApi
        .queryList({ targetId: row.targetId, startTime: dateFormat(+new Date() - 60 * 60 * 1000), endTime: dateFormat() })
        .then(({ data }) => {
          travelList[row.targetId].list = data.reverse();
          if (data.length > 0 && data[0].targetId === showShipId) {
            DrawJS.drawTravel(map, travelList[row.targetId].list, `tarvel_${row.targetId}`);
          }
        });
    } else {
      DrawJS.drawTravel(map, travelList[row.targetId].list, `tarvel_${row.targetId}`);
    }
    MethodsJS.handleShipPoint(map, row, params);
  }

  let blackTimeout = null;
  function drawBlackLine(row) {
    clearTimeout(blackTimeout);
    DrawJS.removeLayer(mapTarget, 'tarvel_black');
    let startTime = +new Date(row.startTime) - 30 * 60 * 1000;
    let endTime = +new Date(row.endTime) + 30 * 60 * 1000;
    fusionTrackApi
      .queryList({
        targetId: row.mmsi,
        startTime: dateFormat(new Date(startTime)),
        endTime: dateFormat(new Date(endTime)),
      })
      .then(({ data }) => {
        DrawJS.drawTravel(mapTarget, data, 'tarvel_black');
      });
    setTimeout(() => {
      DrawJS.removeLayer(mapTarget, 'tarvel_black');
    }, 3 * 1000);
  }

  // 船舶驶出监控区域
  function removeShipByMqtt(row) {
    for (let item of row) {
      // 删除船舶
      ShipJS.removeShip(sourceList.ship, { targetId: item });
      // 清空轨迹
      DrawJS.removeLayer(mapTarget, `tarvel_${item}`);
      // 清理缓存
      delete travelList[item];
    }
  }

  // 初始化获取船舶并绘制对应的轨迹
  function drawAISListLast(list) {
    for (let item of list) {
      mqttGetGps(item);
      // 获取轨迹
      fusionTrackApi.queryList({ targetId: item.targetId }).then(({ data }) => {
        travelList[item.targetId] = {
          type: 'local',
          list: data.reverse(),
        };
        DrawJS.drawTravel(mapTarget, travelList[item.targetId].list, `tarvel_${item.targetId}`);
      });
    }
  }

  // 绘制区域
  function drawArea() {
    areaApi.queryList().then(({ data }) => {
      // 获取当前闪烁的区域
      areaList.value.forEach((item2) => {
        const row = data.find((item1) => item1.areaId === item2.areaId);
        if (row) {
          row.state = item2.state;
        }
      });
      areaList.value = data.filter((m) => m.isShowArea);
      DrawJS.drawArea(mapTarget, areaList.value);
    });
  }

  // 区域闪烁 state区分当前区域是需要闪烁还是熄灭
  function flickerAreaByState(list, state) {
    const statePriority = {
      0: 2, // 关注 : 中权重
      1: 3, // 报警 : 高权重
      2: 1, // 无状态 : 低权重
    };

    for (let item of areaList.value) {
      if (!item.state) {
        item.state = '2';
      }
      let eventItem = list.find((m) => m.areaId === item.areaId);
      // 如果有事件，去判断是否需要变更状态
      if (eventItem) {
        if (statePriority[eventItem.state] > statePriority[item.state]) {
          // 现在发生的事件比之前要紧急，则覆盖
          item.state = state;
        }
      } else {
        // 因为入参是单类型的事件，所以不代表就真的没有事件
        // 根据当前入参的state，若和之前事件状态一致，代表事件真的没了，则赋值 无状态2
        if (state === item.state) {
          item.state = '2';
        }
      }
    }

    DrawJS.drawArea(mapTarget, areaList.value);
    console.log('重置报警: ', JSON.stringify(areaList.value.map((m) => m.state)));
  }

  function flickerArea(list) {
    const statePriority = {
      0: 2, // 关注 : 中权重
      1: 3, // 报警 : 高权重
      2: 1, // 无状态 : 低权重
    };

    for (let item of areaList.value) {
      item.state = '2';
      let eventItem = list.find((m) => m.areaId === item.areaId);
      // 如果有事件，去判断是否需要变更状态
      if (eventItem) {
        if (statePriority[eventItem.state] > statePriority[item.state]) {
          // 现在发生的事件比之前要紧急，则覆盖
          item.state = eventItem.state;
        }
      }
    }

    DrawJS.drawArea(mapTarget, areaList.value);
    console.log('重置报警: ', JSON.stringify(areaList.value.map((m) => m.state)));
  }

  function uploadConfig(type) {
    switch (type) {
      case 'area':
        drawArea(mapTarget);
        break;
      case 'camera':
        MethodsJS.drawCamera(mapTarget);
        break;
      case 'radar':
        MethodsJS.drawRadar(mapTarget);
        break;
      default:
      //
    }
  }

  // tool
  function handleOperat(row) {
    const fnList = {
      handleDraw: () => {
        DrawMethods.measure(mapTarget, row.params);
      },
      handleERBL: () => {
        DrawMethods.measureERBL(mapTarget);
      },
      handleClearDraw: () => {
        var layerTmp = mapTarget
          .getLayers()
          .getArray()
          .find((m) => m.get('name') === 'DRAW');
        if (layerTmp) DrawMethods.handleClearDraw(layerTmp, mapTarget);
      },
      handleZoom: () => {
        const view = mapTarget.getView();
        const zoom = view.getZoom();
        view.setZoom(zoom + row.params);
      },
    };
    fnList[row.fn](row);
  }

  // 摄像头跟踪
  function changeCamera(row) {
    const shipList = travelList[row.targetId]?.list || [];
    if (shipList.length > 0) {
      const shipInfo = shipList[shipList.length - 1];
      const data = {
        longitude: row.VesselLongitude || shipInfo.longitude,
        latitude: row.VesselLatitude || shipInfo.latitude,
        cameraId: row.cameraId,
      };
      MethodsJS.drawCameraRange(mapTarget, data);
    }
  }

  // 显示水位计
  function showWatchPoint(row) {
    waterData.value = Object.assign({}, waterData.value, row);
    if (waterData.value.status) {
      DrawJS.drawWaterPoint(mapTarget, [
        {
          longitude: 119.452047,
          latitude: 29.174735,
          value: waterData.value.value,
        },
      ]);
    } else {
      UtilMethods.removeDomByClassName('water_point_tips');
    }
  }

  function handleRotate(rotate) {
    mapTarget.getView().setRotation(rotate);
  }

  defineExpose({
    deviceSelect,
    mqttGetGps,
    removeShipByMqtt,
    drawAISListLast,
    uploadConfig,
    changeCamera,
    showWatchPoint,
    flickerArea,
    drawBlackLine,
  });
</script>

<style lang="less" scoped>
  @import './index.less';
</style>

<style lang="less">
  @import './tips.less';
  .ol-scale-line {
    background: rgba(255, 255, 255, 0.6);
    padding: 2px;
    font-size: 12px;
    z-index: 9999;
    position: fixed;
    left: 400px;
    bottom: 20px;
    border: 1px solid #333;
    border-top: 0;
  }
</style>
